#pragma once

#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include "Socket.hpp"
#include "Epoller.hpp"
#include "log.hpp"
#include "NoCopy.hpp"

uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);

class Server : public NoCopy
{
public:
    Server(uint16_t port = 8080)
    : _port(port)
    , _listen_sock(new Sock())
    , _epoller(new Epoller())
    {}

    void Init()
    {
        _listen_sock->Socket();
        _listen_sock->Bind(_port);
        _listen_sock->Listen();
    }

    void Run()
    {
        //红黑树插入监听套接字
        _epoller->EpollerCtl(EPOLL_CTL_ADD, _listen_sock->Fd(), EVENT_IN);

        struct epoll_event revents[_maxevents];
        while(1)
        {
            //获取就绪队列
            int ready_num = _epoller->EpollerWait(revents, _maxevents);
            if(ready_num > 0)
            {
                //有n个事件就绪
                Dispatcher(ready_num, revents);
            }
            else if(ready_num == 0)
            {
                //等待超时
                lg(Info, "time out");
            }
            else
            {
                //出错
                lg(Error, "EpollerWait error");
            }
        }
    }

    ~Server()
    {
        if(_listen_sock->Fd() >= 0)
        {
            _listen_sock->Close();
        }
    }

private:
    void Dispatcher(int ready_num, struct epoll_event revents[])
    {
        for(int i=0; i<ready_num; i++)
        {
            //获取就绪节点的fd和对应事件
            int fd = revents[i].data.fd;
            uint32_t event = revents[i].events;

            //先判断事件，再判断fd
            //读事件
            if(event & EVENT_IN)
            {
                if(fd == _listen_sock->Fd())
                {
                    Accepter();
                }
                else
                {
                    Reader(fd);
                }
            }
            //写事件
            else if(event & EVENT_OUT)
            {
                //...
            }
        }
    }

    void Accepter()
    {
        //获取连接，获得新fd
        std::string client_ip;
        uint16_t client_port;
        int accept_fd = _listen_sock->Accept(&client_ip, &client_port);
        if(accept_fd > 0)
        {
            //红黑树插入新fd
            _epoller->EpollerCtl(EPOLL_CTL_ADD, accept_fd, EVENT_IN);
        }
    }

    void Reader(int fd)
    {
        char buffer[1024];
        int r = read(fd, buffer, sizeof(buffer)-1);
        if(r > 0)
        {
            buffer[r] = 0;
            std::cout << "Client# " << buffer << std::endl;

            std::string msg = "Server# ";
            msg += buffer;
            write(fd, msg.c_str(), msg.size());
        }
        else if(r == 0)
        {
            //对方退出了，红黑树删除节点，先删除再关闭
            _epoller->EpollerCtl(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
        else
        {
            lg(Error, "read err: %s[%d]", strerror(errno), errno);
            
            _epoller->EpollerCtl(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
    }

private:
    static const int _maxevents = 64; //就绪队列的容量
    std::shared_ptr<Sock> _listen_sock; //监听套接字
    std::shared_ptr<Epoller> _epoller; //epoll对象
    uint16_t _port; //端口
};